
package org.apache.solr.search;

import org.apache.lucene.queries.function.BoostedQuery;
import org.apache.lucene.queries.function.FunctionQuery;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.QueryValueSource;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.Query;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;

/**
 * Create a boosted query from the input value.  The main value is the query to be boosted.
 * <br>Other parameters: <code>b</code>, the function query to use as the boost.
 * <p>Example: <code>{!boost b=log(popularity)}foo</code> creates a query "foo"
 * which is boosted (scores are multiplied) by the function query <code>log(popularity)</code>.
 * The query to be boosted may be of any type.
 *
 * <p>Example: <code>{!boost b=recip(ms(NOW,mydatefield),3.16e-11,1,1)}foo</code> creates a query "foo"
 * which is boosted by the date boosting function referenced in
 * {@link org.apache.lucene.queries.function.valuesource.ReciprocalFloatFunction}
 */
public class BoostQParserPlugin extends QParserPlugin {

    public static String NAME = "boost";
    public static String BOOSTFUNC = "b";

    @Override
    public void init(NamedList args) {
    }

    @Override
    public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
        return new QParser(qstr, localParams, params, req) {
            QParser baseParser;
            ValueSource vs;
            String b;

            @Override
            public Query parse() throws ParseException {
                b = localParams.get(BOOSTFUNC);
                baseParser = subQuery(localParams.get(QueryParsing.V), null);
                Query q = baseParser.getQuery();

                if (b == null) {
                    return q;
                }
                Query bq = subQuery(b, FunctionQParserPlugin.NAME).getQuery();
                if (bq instanceof FunctionQuery) {
                    vs = ((FunctionQuery) bq).getValueSource();
                }
                else {
                    vs = new QueryValueSource(bq, 0.0f);
                }
                return new BoostedQuery(q, vs);
            }

            @Override
            public String[] getDefaultHighlightFields() {
                return baseParser.getDefaultHighlightFields();
            }

            @Override
            public Query getHighlightQuery() throws ParseException {
                return baseParser.getHighlightQuery();
            }

            @Override
            public void addDebugInfo(NamedList<Object> debugInfo) {
                // encapsulate base debug info in a sub-list?
                baseParser.addDebugInfo(debugInfo);
                debugInfo.add("boost_str", b);
                debugInfo.add("boost_parsed", vs);
            }
        };
    }
}
